home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HPAVC
/
HPAVC CD-ROM.iso
/
SNNSV32.ZIP
/
SNNSv3.2
/
kernel
/
sources
/
dlvq_learn.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-04-25
|
29KB
|
1,104 lines
/*****************************************************************************
FILE : dlvq_learn.c
SHORTNAME :
SNNS VERSION : 3.2
PURPOSE : Functions of DLVQ
NOTES :
AUTHOR : Michael Schmalzl
DATE : 5.2.93
CHANGED BY : Michael Vogt, Guenter Mamier
IDENTIFICATION : @(#)dlvq_learn.c 1.9 4/6/94
SCCS VERSION : 1.9
LAST CHANGE : 4/6/94
Copyright (c) 1990-1994 SNNS Group, IPVR, Univ. Stuttgart, FRG
******************************************************************************/
#include <stdio.h>
#include <math.h>
#include <time.h>
#include <memory.h>
#include <malloc.h>
#include <values.h>
#include "kr_typ.h" /* Kernel Types and Constants */
#include "kr_const.h" /* Constant Declarators for SNNS-Kernel */
#include "kr_def.h" /* Default Values */
#include "kernel.h" /* kernel function prototypes */
#include "kr_ui.h"
#include "kr_mac.h" /* Kernel Macros */
#include "kr_ui.h"
#include "cc_mac.h"
#include "kr_newpattern.h"
#include "cc_rcc.h"
#include "dlvq_type.h"
#include "dlvq_learn.ph"
/*****************************************************************************
FUNCTION : sortHiddenUnitsByClasses
PURPOSE : Sorts the hidden units by its class.
NOTES :
UPDATE : 5.2.93
******************************************************************************/
static void sortHiddenUnitsByClasses(int left, int right)
{
int i,last;
struct Unit *temp;
if(left >= right ){
return;
}
temp = FirstHiddenUnitPtr[left];
FirstHiddenUnitPtr[left] = FirstHiddenUnitPtr[(left+right)/2];
FirstHiddenUnitPtr[(left+right)/2] = temp;
last = left;
for(i=left+1;i<=right;i++){
if(FirstHiddenUnitPtr[i]->bias < FirstHiddenUnitPtr[left]->bias) {
temp = FirstHiddenUnitPtr[++last];
FirstHiddenUnitPtr[last]=FirstHiddenUnitPtr[i];
FirstHiddenUnitPtr[i]=temp;
}
}
temp = FirstHiddenUnitPtr[left];
FirstHiddenUnitPtr[left]=FirstHiddenUnitPtr[last];
FirstHiddenUnitPtr[last] = temp;
sortHiddenUnitsByClasses(left,last);
sortHiddenUnitsByClasses(last+1,right);
}
/*****************************************************************************
FUNCTION : getNoOfClasses
PURPOSE : Looks how many different classes exist and checks whether the
no. of the first class is zero.
NOTES :
UPDATE : 5.2.93
******************************************************************************/
krui_err getNoOfClasses(int startPattern, int endPattern)
{
int p,patternClass=0,maxPatternClass=0,minPatternClass=0;
int *tmpArray,counter,class;
int start, end;
int pat, sub_pat;
Patterns out_pat;
KernelErrorCode = kr_initSubPatternOrder(startPattern, endPattern);
if (KernelErrorCode != KRERR_NO_ERROR)
return KernelErrorCode;
start = kr_AbsPosOfFirstSubPat(startPattern);
end = kr_AbsPosOfFirstSubPat(endPattern);
end += kr_NoOfSubPatPairs(endPattern) - 1;
for(p=start; p<=end;p++){
kr_getSubPatternByNo(&pat, &sub_pat, p);
out_pat = kr_getSubPatData(pat, sub_pat, OUTPUT, NULL);
patternClass = *out_pat;
if(patternClass < minPatternClass){
minPatternClass = patternClass;
}
if(patternClass > maxPatternClass){
maxPatternClass = patternClass;
}
}
if(minPatternClass != 0){
return(DLVQ_ERROR2); /* There exists a class smaller than 0 */
}
counter = 0;
p = start;
tmpArray = (int *)calloc(maxPatternClass+1,sizeof(int));
while((counter != (maxPatternClass+1)) && (p <= end)){
kr_getSubPatternByNo(&pat, &sub_pat, p++);
out_pat = kr_getSubPatData(pat, sub_pat, OUTPUT, NULL);
class = *out_pat;
if(tmpArray[class] == 0){
counter++;
tmpArray[class] = 1;
}
}
free(tmpArray);
if(counter != (maxPatternClass+1)){
return(DLVQ_ERROR1); /* There are empty classes */
}
noOfClasses = maxPatternClass+1;
return(KRERR_NO_ERROR);
}
/*****************************************************************************
FUNCTION : allocMixupArray
PURPOSE : Allocate the storage of the "mixupArray".
NOTES :
UPDATE : 5.2.93
******************************************************************************/
static void allocMixupArray(void)
{
int i,j;
/* free storage */
for(i=0;i<oldNoOfClasses;i++) {
for(j=0;j<oldNoOfClasses;j++) {
free(mixupArray[i][j].link);
}
}
for(i=0;i<oldNoOfClasses;i++) {
free(mixupArray[i]);
}
if(mixupArray != NULL) {
free(mixupArray);
mixupArray = NULL;
}
/* alloc storage */
mixupArray = (struct MIX_UP **)calloc(noOfClasses,sizeof(struct MIX_UP *));
for(i=0;i<noOfClasses;i++) {
mixupArray[i] =
(struct MIX_UP *)calloc(noOfClasses,sizeof(struct MIX_UP));
}
for(i=0;i<noOfClasses;i++) {
for(j=0;j<noOfClasses;j++) {
mixupArray[i][j].link =
(double *)calloc(NoOfInputUnits,sizeof(double));
}
}
}
/*****************************************************************************
FUNCTION : allocLastInsertedUnitArray
PURPOSE : Allocate the storage of the array "lastInsertedUnitArray".
NOTES :
UPDATE : 5.2.93
******************************************************************************/
static void allocLastInsertedUnitArray(void)
{
/* free storage */
if(lastInsertedUnitArray != NULL){
free(lastInsertedUnitArray);
lastInsertedUnitArray = NULL;
}
/* alloc storage */
lastInsertedUnitArray = (int *)calloc(noOfClasses,sizeof(int));
}
/*****************************************************************************
FUNCTION : allocInitialUnitArray
PURPOSE : Allocate the storage of the array "initialUnitArray"
NOTES :
UPDATE : 5.2.93
******************************************************************************/
void allocInitialUnitArray(void)
{
int i;
/* free storage */
for(i=0;i<oldNoOfClasses;i++) {
free(initialUnitArray[i].link);
}
if(initialUnitArray != NULL) {
free(initialUnitArray);
initialUnitArray = NULL;
}
/* alloc storage */
initialUnitArray =
(struct MIX_UP *)calloc(noOfClasses,sizeof(struct MIX_UP));
for(i=0;i<noOfClasses;i++) {
initialUnitArray[i].link =
(double *)calloc(NoOfInputUnits,sizeof(double));
}
}
/*****************************************************************************
FUNCTION : normPatterns
PURPOSE : Norm all patterns.
NOTES : This function is of no permanent effect since the manipulation
of the input pattern takes place on a copy of the original data.
Patterns must be normalized before use of DLVQ !!!!!
Therefore the body of the function is commented out. The original code is
left in place to demonstrate the necessary operation. (M. Vogt)
UPDATE : 5.2.93
******************************************************************************/
void normPatterns(int startPattern, int endPattern)
{
/* see NOTES of funtion header */
/*
double sum,sqrtSum;
Patterns in_pat,in_patStorage;
int p,i;
int start, end;
int pat, sub;
int count;
KernelErrorCode = kr_initSubPatternOrder(startPattern,endPattern);
start = kr_AbsPosOfFirstSubPat(startPattern);
end = kr_AbsPosOfFirstSubPat(endPattern);
end += kr_NoOfSubPatPairs(endPattern) - 1;
for(p=start; p<=end;p++){
kr_getSubPatternByNo(&pat,&sub,p);
in_pat = kr_getSubPatData(pat,sub,INPUT,&count);
sum = 0.0;
in_patStorage = in_pat;
for(i=0;i<count;i++){
sum += (*in_pat) * (*in_pat);
in_pat++;
}
sqrtSum = sqrt(sum);
in_pat = in_patStorage;
for(i=0;i<count;i++){
*in_pat = *in_pat / sqrtSum;
in_pat++;
}
}
*/
}
/*****************************************************************************
FUNCTION : normReferenceVec
PURPOSE :
NOTES :
UPDATE : 5.2.93
******************************************************************************/
static void normReferenceVec(struct Unit *hiddenUnitPtr)
{
double sum,sqrtSum;
struct Link *linkPtr;
sum = 0.0;
FOR_ALL_LINKS(hiddenUnitPtr,linkPtr) {
sum += linkPtr->weight * linkPtr->weight;
}
sqrtSum = sqrt(sum);
FOR_ALL_LINKS(hiddenUnitPtr,linkPtr){
linkPtr->weight = linkPtr->weight / sqrtSum;
}
}
/*****************************************************************************
FUNCTION : moveVec
PURPOSE : Train the vectors.
NOTES :
UPDATE : 5.2.93
******************************************************************************/
static void moveVec(struct Unit *correctReferenceVec, float learnParam1,
struct Unit *wrongReferenceVec, float learnParam2)
{
struct Link *linkPtr;
FOR_ALL_LINKS(correctReferenceVec,linkPtr){
linkPtr->weight += learnParam1 * (linkPtr->to->act - linkPtr->weight);
}
normReferenceVec(correctReferenceVec);
FOR_ALL_LINKS(wrongReferenceVec,linkPtr){
linkPtr->weight -= learnParam2 * (linkPtr->to->act - linkPtr->weight);
}
normReferenceVec(wrongReferenceVec);
}
/*****************************************************************************
FUNCTION :
PURPOSE :
NOTES :
UPDATE : 5.2.93
******************************************************************************/
static void writeVectorToMixupArray(int correctClass, int wrongClass,
int patternNo, int sub_pat_no)
{
Patterns in_pat;
double *link=NULL;
int i,count;
/* calculate startaddress for input pattern array */
in_pat = kr_getSubPatData(patternNo,sub_pat_no,INPUT,&count);
link = mixupArray[correctClass][wrongClass].link;
for(i=0;i<count;i++){
link[i] = (double)in_pat[i];
}
}
/*****************************************************************************
FUNCTION : initInitialUnitArray
PURPOSE : Init the array "initialUnitArray".
NOTES :
UPDATE : 5.2.93
******************************************************************************/
void initInitialUnitArray(int startPattern, int endPattern)
{
int p,i,j;
Patterns in_pat;
Patterns out_pat;
int start, end;
int pat, sub;
int count;
KernelErrorCode = kr_initSubPatternOrder(startPattern,endPattern);
start = kr_AbsPosOfFirstSubPat(startPattern);
end = kr_AbsPosOfFirstSubPat(endPattern);
end += kr_NoOfSubPatPairs(endPattern) - 1;
for(p=start; p<=end;p++){
kr_getSubPatternByNo(&pat,&sub,p);
in_pat = kr_getSubPatData(pat,sub,INPUT,&count);
out_pat = kr_getSubPatData(pat,sub,OUTPUT,NULL);
for(i=0;i<count;i++){
(initialUnitArray[(int) *out_pat].link)[i] = *in_pat++;
initialUnitArray[(int) *out_pat].counter++;
}
}
for(i=0;i<noOfClasses;i++){
for(j=0;j<count;j++){
(initialUnitArray[i].link)[j] /= initialUnitArray[i].counter;
}
}
}
/*****************************************************************************
FUNCTION : initFirstUnit
PURPOSE : Init the links of a class unit. Remember: At the beginning of
the learning there exist no hidden units. The first step of
the algorithm inserts for every class a hidden unit. This
functions inits the links of this first units. The array
"initialUnitArray" contains for every class the average
activation over all patterns.
NOTES :
UPDATE : 5.2.93
******************************************************************************/
static void initFirstUnit(struct Unit *hiddenUnitPtr, int class)
{
int i;
struct Link *linkPtr;
struct Unit *inputUnitPtr;
i = 0;
FOR_ALL_UNITS(inputUnitPtr){
if(IS_INPUT_UNIT(inputUnitPtr) && UNIT_IN_USE(inputUnitPtr)){
inputUnitPtr->act = (initialUnitArray[class].link)[i++];
}
}
hiddenUnitPtr->bias = class;
FOR_ALL_LINKS(hiddenUnitPtr,linkPtr) {
linkPtr->weight = linkPtr->to->act;
}
normReferenceVec(hiddenUnitPtr);
}
/*****************************************************************************
FUNCTION : deleteAllLinksOfTheOutputUnit
PURPOSE :
NOTES :
UPDATE : 5.2.93
******************************************************************************/
static krui_err deleteAllLinksOfTheOutputUnit(void)
{
KernelErrorCode = krui_setCurrentUnit(GET_UNIT_NO(*FirstOutputUnitPtr));
ERROR_CHECK;
krui_deleteAllInputLinks();
krui_deleteAllOutputLinks();
return(KRERR_NO_ERROR);
}
/*****************************************************************************
FUNCTION : calculateUnitXYPos
PURPOSE : Calculates the position of the current input, hidden and output
layer.
NOTES :
UPDATE : 5.2.93
******************************************************************************/
static void calculateUnitXYPos(void)
{
int xPos,yPos,maxXPos=0,maxYPos,minXPos=0,minYPos=0,i,
xOffset,yOffset,bias,h;
struct Unit *inputUnitPtr=NULL,*hiddenUnitPtr;
inputUnitPtr = *FirstInputUnitPtr;
maxXPos = minXPos = GET_UNIT_XPOS(inputUnitPtr);
maxYPos = minYPos = GET_UNIT_YPOS(inputUnitPtr);
/* find maxXPos ... of the input layer */
FOR_ALL_INPUT_UNITS(inputUnitPtr,i) {
xPos = GET_UNIT_XPOS(inputUnitPtr);
yPos = GET_UNIT_YPOS(inputUnitPtr);
if(xPos > maxXPos) {
maxXPos = xPos;
}
if(xPos < minXPos){
minXPos = xPos;
}
if(yPos > maxYPos) {
maxYPos = yPos;
}
if(yPos < minYPos){
minYPos = yPos;
}
}
xOffset = minXPos - 2;
yOffset = minYPos - 2;
FOR_ALL_INPUT_UNITS(inputUnitPtr,i){
SET_UNIT_XPOS(inputUnitPtr,GET_UNIT_XPOS(inputUnitPtr) - xOffset);
SET_UNIT_YPOS(inputUnitPtr,GET_UNIT_YPOS(inputUnitPtr) - yOffset);
}
bias = (*FirstHiddenUnitPtr)->bias;
xPos = (maxXPos - xOffset + 3);
yPos = 1;
FOR_ALL_HIDDEN_UNITS(hiddenUnitPtr,h){
if(bias == hiddenUnitPtr->bias){
yPos++;
}else{
xPos++;
bias = hiddenUnitPtr->bias;
yPos = 2;
}
SET_UNIT_XPOS(hiddenUnitPtr,xPos);
SET_UNIT_YPOS(hiddenUnitPtr,yPos);
}
SET_UNIT_XPOS(*FirstOutputUnitPtr,xPos+3);
SET_UNIT_YPOS(*FirstOutputUnitPtr,2);
}
/*****************************************************************************
FUNCTION : insertNewUnits
PURPOSE : Inserts new hidden units to the net. The weights of the links
are stored in the "mixupArray".
NOTES :
UPDATE : 5.2.93
******************************************************************************/
static krui_err insertNewUnits(void)
{
int i,j,k,maxCount,maxJ=0,newUnit;
double sum,sqrtSum,weight;
struct Unit *newUnitPtr,*inputUnitPtr;
struct Link *linkPtr;
for(i=0;i<noOfClasses;i++) {
maxCount = 0;
for(j=0;j<noOfClasses;j++){
if(mixupArray[i][j].counter > maxCount) {
maxCount = mixupArray[i][j].counter;
maxJ = j;
}
}
if(maxCount != 0){
/* Generate new unit */
newUnit =
KernelErrorCode =
krui_copyUnit(lastInsertedUnitArray[i],INPUTS_AND_OUTPUTS);
if(KernelErrorCode < 0){
ERROR_CHECK;
}
KernelErrorCode = KRERR_NO_ERROR;
newUnitPtr = kr_getUnitPtr(lastInsertedUnitArray[i] = newUnit);
newUnitPtr->unit_pos.y += 1;
/*init new unit */
sum = 0.0;
k = 0;
FOR_ALL_UNITS(inputUnitPtr){
if(IS_INPUT_UNIT(inputUnitPtr) && UNIT_IN_USE(inputUnitPtr)) {
weight =
inputUnitPtr->act =
((mixupArray[i][maxJ].link)[k++] /
mixupArray[i][maxJ].counter);
sum += weight * weight;
}
}
sqrtSum = sqrt(sum);
FOR_ALL_LINKS(newUnitPtr,linkPtr) {
linkPtr->weight = linkPtr->to->act / sqrtSum;
}
}
}
initMixupArray();
return(KRERR_NO_ERROR);
}
/*****************************************************************************
FUNCTION : initMixupArray
PURPOSE : Init the array "mixupArray".
NOTES :
UPDATE : 5.2.93
******************************************************************************/
static void initMixupArray(void)
{
int i,j,sizeOfInputVector;
sizeOfInputVector = sizeof(double) * NoOfInputUnits;
for(i=0;i<noOfClasses;i++) {
for(j=0;j<noOfClasses;j++){
if(mixupArray[i][j].counter != 0){
(void)memset(mixupArray[i][j].link,0,sizeOfInputVector);
mixupArray[i][j].counter = 0;
}
}
}
}
/*****************************************************************************
FUNCTION : printMixupArray
PURPOSE :
NOTES :
UPDATE : 5.2.93
******************************************************************************/
static void printMixupArray(int cycle)
{
int i,j;
printf("Cycle %d \n",cycle+1);
printf("Total number of incorrectly classified items: %d \n",
wrongClassCounter);
printf("Array of classified items:\n\n");
for(i=0;i<noOfClasses;i++) {
for(j=0;j<noOfClasses;j++){
printf("%d ",mixupArray[i][j].counter);
}
printf("\n");
}
printf("\n\n");
}
/*****************************************************************************
FUNCTION : dlvq_trainNet
PURPOSE :
NOTES :
UPDATE : 5.2.93
******************************************************************************/
static void dlvq_trainNet(int noOfTrainingCycles, int startPattern,
int endPattern, float learnParam1, float learnParam2)
{
struct Unit *correctMaxActivatedUnitPtr=NULL,
*wrongMaxActivatedUnitPtr=NULL,
*inputUnitPtr,
*hiddenUnitPtr;
double correctMaxAct,wrongMaxAct,act;
Patterns in_pat;
Patterns out_pat;
int i,h,p,j,noOfTrainingCyclesMinus1=noOfTrainingCycles-1;
struct Link *linkPtr;
int start, end;
int pat, sub;
for(j=0;j<noOfTrainingCycles;j++){
KernelErrorCode = kr_initSubPatternOrder(startPattern,endPattern);
start = kr_AbsPosOfFirstSubPat(startPattern);
end = kr_AbsPosOfFirstSubPat(endPattern);
end += kr_NoOfSubPatPairs(endPattern) - 1;
for(p=start; p<=end;p++){
kr_getSubPatternByNo(&pat,&sub,p);
in_pat = kr_getSubPatData(pat,sub,INPUT,NULL);
out_pat = kr_getSubPatData(pat,sub,OUTPUT,NULL);
FOR_ALL_INPUT_UNITS(inputUnitPtr,i){
inputUnitPtr->Out.output = inputUnitPtr->act = *in_pat++;
}
correctMaxAct = -1.0;
wrongMaxAct = -1.0;
correctMaxActivatedUnitPtr = NULL;
wrongMaxActivatedUnitPtr = NULL;
FOR_ALL_HIDDEN_UNITS(hiddenUnitPtr,h) {
act = 0.0;
FOR_ALL_LINKS(hiddenUnitPtr,linkPtr) {
act += linkPtr->weight * linkPtr->to->act;
}
hiddenUnitPtr->act = act;
if((((int)hiddenUnitPtr->bias) == ((int) *out_pat)) &&
(act >= correctMaxAct)){
correctMaxAct = act;
correctMaxActivatedUnitPtr = hiddenUnitPtr;
}
else if((((int)hiddenUnitPtr->bias)!=((int) *out_pat)) &&
(act >= wrongMaxAct)){
wrongMaxAct = act;
wrongMaxActivatedUnitPtr = hiddenUnitPtr;
}
}
if(correctMaxAct <= wrongMaxAct){
wrongClassCounter++;
mixupArray[(int) *out_pat]
[(int)wrongMaxActivatedUnitPtr->bias].counter++;
if(j == noOfTrainingCyclesMinus1){
writeVectorToMixupArray(
(int)correctMaxActivatedUnitPtr->bias,
(int)wrongMaxActivatedUnitPtr->bias,
pat,sub);
}else{
moveVec(correctMaxActivatedUnitPtr,learnParam1,
wrongMaxActivatedUnitPtr,learnParam2);
}
}
} /* end: noOfTrainingCycles */
printMixupArray(j);
if(wrongClassCounter == 0){
continueLearning = 0;
return;
}
if(j!=noOfTrainingCyclesMinus1){
initMixupArray();
wrongClassCounter = 0;
}
}
}
/*****************************************************************************
FUNCTION : initLastInsertedUnitArray
PURPOSE : Init the array lastInsertedUnitArray. This array contains the
position of the last inserted unit. There is an entry for
every class.
NOTES :
UPDATE : 5.2.93
******************************************************************************/
static void initLastInsertedUnitArray(void)
{
int h,bias;
struct Unit *hiddenUnitPtr=NULL,*lastUnitPtr=NULL;
bias = (*FirstHiddenUnitPtr)->bias;
FOR_ALL_HIDDEN_UNITS(hiddenUnitPtr,h){
if(((int)(hiddenUnitPtr->bias)) == ((int)bias)) {
lastUnitPtr = hiddenUnitPtr;
}else{
lastInsertedUnitArray[(int)lastUnitPtr->bias] =
GET_UNIT_NO(lastUnitPtr);
bias = hiddenUnitPtr->bias;
lastUnitPtr = hiddenUnitPtr;
}
}
lastInsertedUnitArray[(int)lastUnitPtr->bias]=GET_UNIT_NO(lastUnitPtr);
}
/*****************************************************************************
FUNCTION : dlvq_setPointers
PURPOSE : Calculates the beginning of the input, hidden, output
units in the topo_ptr_array.
NOTES :
UPDATE : 5.2.93
******************************************************************************/
krui_err dlvq_setPointers(void)
{
FirstInputUnitPtr = (struct Unit **)(&topo_ptr_array[1]);
if(*(FirstInputUnitPtr-1)!=NULL) CC_ERROR(KRERR_CC_ERROR1);
FirstHiddenUnitPtr = FirstInputUnitPtr + NoOfInputUnits + 1;
if(*(FirstHiddenUnitPtr-1)!=NULL) CC_ERROR(KRERR_CC_ERROR1);
FirstOutputUnitPtr = FirstHiddenUnitPtr + NoOfHiddenUnits + 1;
if(*(FirstOutputUnitPtr-1)!=NULL) CC_ERROR(KRERR_CC_ERROR1);
return(KRERR_NO_ERROR);
}
/*****************************************************************************
FUNCTION : generateMissingClassHiddenUnits
PURPOSE : If all hidden units of a class are removed, this functions
generates a new first hidden unit.
NOTES :
UPDATE : 5.2.93
******************************************************************************/
void generateMissingClassHiddenUnits(int *generatedNewUnit)
{
struct Unit *hiddenUnitPtr;
int i,h;
*generatedNewUnit = 0;
for(i=0;i<noOfClasses;i++){
lastInsertedUnitArray[i] = 0;
}
FOR_ALL_HIDDEN_UNITS(hiddenUnitPtr,h){
lastInsertedUnitArray[(int)hiddenUnitPtr->bias] = 1;
}
for(i=0;i<noOfClasses;i++){
if(lastInsertedUnitArray[i] == 0) {
(void)insertFirstUnit(&hiddenUnitPtr);
initFirstUnit(hiddenUnitPtr,i);
*generatedNewUnit = 1;
}else{
lastInsertedUnitArray[i] = 0;
}
}
}
/*****************************************************************************
FUNCTION : insertFirstUnit
PURPOSE : Inserts the first hidden units to the net. For every class one
unit.
NOTES :
UPDATE : 5.2.93
******************************************************************************/
static krui_err insertFirstUnit(struct Unit **hiddenUnitPtr)
{
int hiddenUnit=0;
struct Unit *inputUnitPtr;
hiddenUnit = KernelErrorCode = krui_createDefaultUnit();
if(KernelErrorCode < 0) {
ERROR_CHECK;
}
KernelErrorCode = krui_setUnitTType(hiddenUnit,HIDDEN);
ERROR_CHECK;
KernelErrorCode = krui_setUnitActFunc(hiddenUnit,"Act_Identity");
ERROR_CHECK;
*hiddenUnitPtr = kr_getUnitPtr(hiddenUnit);
KernelErrorCode = krui_setCurrentUnit(hiddenUnit);
ERROR_CHECK;
/* generate links between hidden unit and input units */
FOR_ALL_UNITS(inputUnitPtr) {
if(IS_INPUT_UNIT(inputUnitPtr) && UNIT_IN_USE(inputUnitPtr)){
KernelErrorCode = krui_createLink(GET_UNIT_NO(inputUnitPtr),0.0);
ERROR_CHECK;
}
}
/* generate a link between the output unit and the hidden unit */
KernelErrorCode = krui_setCurrentUnit(GET_UNIT_NO(*FirstOutputUnitPtr));
ERROR_CHECK;
KernelErrorCode = krui_createLink(hiddenUnit,1.0);
ERROR_CHECK;
return(KRERR_NO_ERROR);
}
/*****************************************************************************
FUNCTION : allocArrays
PURPOSE :
NOTES :
UPDATE : 5.2.93
******************************************************************************/
void allocArrays(void)
{
allocMixupArray();
allocLastInsertedUnitArray();
}
/*****************************************************************************
FUNCTION : generateTmpTopoPtrArray
PURPOSE : Generates a topo_ptr_array for local use.
NOTES :
UPDATE : 5.2.93
******************************************************************************/
static void generateTmpTopoPtrArray(void)
{
struct Unit *unitPtr;
TopoPtrArray tmp_array;
if(topo_ptr_array != NULL) {
free(topo_ptr_array);
}
tmp_array =
topo_ptr_array =
(struct Unit **)calloc(NoOfInputUnits+5,sizeof(struct Unit *));
*tmp_array = NULL;
tmp_array++;
FOR_ALL_UNITS(unitPtr){
if(IS_INPUT_UNIT(unitPtr) && UNIT_IN_USE(unitPtr)){
*tmp_array = unitPtr;
tmp_array++;
}
}
*tmp_array = NULL;
tmp_array++;
*tmp_array = NULL;
tmp_array++;
FOR_ALL_UNITS(unitPtr){
if(IS_OUTPUT_UNIT(unitPtr) && UNIT_IN_USE(unitPtr)){
*tmp_array = unitPtr;
tmp_array++;
}
}
*tmp_array = NULL;
}
/*****************************************************************************
FUNCTION : freeTmpTopoPtrArray
PURPOSE : Frees the storage of the temporary "topo_ptr_array".
NOTES :
UPDATE : 5.2.93
******************************************************************************/
static void freeTmpTopoPtrArray(void)
{
free(topo_ptr_array);
topo_ptr_array = NULL;
}
/*****************************************************************************
FUNCTION : LEARN_DLVQ
PURPOSE : The main learn routine of DLVQ
NOTES :
UPDATE : 5.2.93
******************************************************************************/
krui_err LEARN_DLVQ(int startPattern, int endPattern, float *ParameterInArray,
int NoOfInParams, float **ParameterOutArray,
int *NoOfOutParams)
{
static int cycleCounter=0,noOfTrainingCycles=0;
struct Unit *unitPtr,*hiddenUnitPtr;
int i,d1,d2,d3,noOfLinks,generatedNewUnit;
static float learnParam1=0.03,learnParam2=0.03;
static float OutParameter[1];
*NoOfOutParams = 1;
*ParameterOutArray = OutParameter;
if(cc_allButtonIsPressed) {
continueLearning = 1;
cycleCounter = 0;
wrongClassCounter = 0;
NoOfInputUnits = NoOfHiddenUnits = NoOfOutputUnits = 0;
FOR_ALL_UNITS(unitPtr) {
if(IS_INPUT_UNIT(unitPtr) && UNIT_IN_USE(unitPtr)) {
NoOfInputUnits++;
}
if(IS_HIDDEN_UNIT(unitPtr) && UNIT_IN_USE(unitPtr)) {
NoOfHiddenUnits++;
}
if(IS_OUTPUT_UNIT(unitPtr) && UNIT_IN_USE(unitPtr)) {
NoOfOutputUnits++;
}
}
if(NoOfOutputUnits != 1){
return(DLVQ_ERROR3); /* Wrong no. of output units */
}
learnParam1 = ParameterInArray[0];
learnParam2 = ParameterInArray[1];
noOfTrainingCycles = (int)ParameterInArray[2];
}
if(newPatternsLoaded){
newPatternsLoaded = 0;
KernelErrorCode = getNoOfClasses(startPattern,endPattern);
ERROR_CHECK;
normPatterns(startPattern,endPattern);
allocInitialUnitArray();
initInitialUnitArray(startPattern,endPattern);
}
if(cc_allButtonIsPressed && (NoOfHiddenUnits == 0)){ /* First time */
allocArrays();
generateTmpTopoPtrArray();
KernelErrorCode = dlvq_setPointers();
ERROR_CHECK;
KernelErrorCode = deleteAllLinksOfTheOutputUnit();
ERROR_CHECK;
for(i=0;i<noOfClasses;i++) {
KernelErrorCode = insertFirstUnit(&hiddenUnitPtr);
ERROR_CHECK;
initFirstUnit(hiddenUnitPtr,i);
}
freeTmpTopoPtrArray();
KernelErrorCode = kr_topoSort(TOPOLOGICAL_FF);
ERROR_CHECK;
KernelErrorCode = dlvq_setPointers();
ERROR_CHECK;
sortHiddenUnitsByClasses(0,noOfClasses-1);
calculateUnitXYPos();
initLastInsertedUnitArray();
NetModified = FALSE;
LearnFuncHasChanged = FALSE;
}else if(cc_allButtonIsPressed && (NoOfHiddenUnits != 0)) {
/* Continue learning */
if(NetModified || LearnFuncHasChanged){
allocArrays();
KernelErrorCode = kr_topoSort(TOPOLOGICAL_FF);
ERROR_CHECK;
KernelErrorCode = dlvq_setPointers();
ERROR_CHECK;
krui_getNetInfo(&d1,&noOfLinks,&d2,&d3);
if(noOfLinks != NoOfInputUnits*NoOfHiddenUnits + NoOfHiddenUnits){
return(DLVQ_ERROR4); /* the network has a wrong topology */
}
generateMissingClassHiddenUnits(&generatedNewUnit);
if(generatedNewUnit) {
KernelErrorCode = kr_topoSort(TOPOLOGICAL_FF);
ERROR_CHECK;
KernelErrorCode = dlvq_setPointers();
ERROR_CHECK;
}
NetModified = FALSE;
LearnFuncHasChanged = FALSE;
}
/* even if the net is not modified you have to do the following
steps for security.
*/
sortHiddenUnitsByClasses(0,NoOfHiddenUnits-1);
calculateUnitXYPos();
initLastInsertedUnitArray();
}
if(cc_allButtonIsPressed){
oldNoOfClasses = noOfClasses;
cc_allButtonIsPressed = 0;
}
if(continueLearning){
initMixupArray();
dlvq_trainNet(noOfTrainingCycles,startPattern,endPattern,
learnParam1,learnParam2);
NET_ERROR(OutParameter) = wrongClassCounter;
if((cycleCounter<(dlvq_numberOfLearnCycles-1)) &&
(wrongClassCounter != 0)){
/*do not insert new hidden units by the last path through the net*/
wrongClassCounter = 0;
cycleCounter++;
KernelErrorCode = insertNewUnits();
ERROR_CHECK;
KernelErrorCode = kr_topoSort(TOPOLOGICAL_FF);
ERROR_CHECK;
KernelErrorCode = dlvq_setPointers();
ERROR_CHECK;
}
}
return(KRERR_NO_ERROR);
}